package cn.yeziji.utils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author gzkemays
 * @date 2021/1/28 16:41
 */
public class DataUtils {
  private static final Logger logger = LoggerFactory.getLogger(DataUtils.class);

  public static <T> T getObjectFromMap(Map<Object, Object> source, Class<T> clazz) {
    try {
      T target = clazz.newInstance();
      Field[] declaredFields = clazz.getDeclaredFields();
      for (Field field : declaredFields) {
        field.setAccessible(true);
        String name = field.getName();
        if (Objects.nonNull(source.get(name))) {
          field.set(target, source.get(field.getName()));
        }
      }
      return target;
    } catch (InstantiationException e) {
      logger.error("无参构造失败");
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      logger.error("实体类：" + clazz + "构造或传参出现异常");
      e.printStackTrace();
    }
    return null;
  }

  /** 对象拷贝（ null 不拷贝） */
  public static Object copyProperties(Object source, Object target) {
    Class<?> targetClass = target.getClass();
    Class<?> sourceClass = source.getClass();
    for (Field sourceField : sourceClass.getDeclaredFields()) {
      // 获取字段的最高权限
      try {
        sourceField.setAccessible(true);
        String key = sourceField.getName();
        Object value = sourceField.get(source);
        Field targetField = targetClass.getDeclaredField(key);
        targetField.setAccessible(true);
        if (Objects.nonNull(value)) {
          targetField.set(target, value);
        } else {
          targetField.set(target, targetField.get(target));
        }
      } catch (NoSuchFieldException | IllegalAccessException e) {
        e.printStackTrace();
      }
    }
    return target;
  }

  /**
   * 截取某个标记之前的字符串
   *
   * @param str
   * @param tag
   * @return
   */
  public static String substrBeforeOfTag(String str, String tag) {
    return str.substring(0, str.indexOf(tag));
  }

  public static String substrBeforeLastOfTag(String str, String tag) {
    return str.substring(0, str.lastIndexOf(tag));
  }

  /**
   * 截取某个标记之后的字符串
   *
   * @param str
   * @param tag
   * @return
   */
  public static String substrAfterOfTag(String str, String tag) {
    return str.substring(str.indexOf(tag) + 1);
  }

  /**
   * 截取两个标记之间的字符串,tag 默认为第一个
   *
   * @param str
   * @param tag
   * @param tag2
   * @return
   */
  public static String substrBetweenOfTag(String str, String tag, String tag2) {
    return str.substring(str.indexOf(tag) + 1, str.indexOf(tag2));
  }

  /**
   * 截取两个标记之间的字符串,首标记从后开始查询
   *
   * @param str
   * @param tag
   * @param tag2
   * @return
   */
  public static String substrBetweenOfLastOfFirstTag(String str, String tag, String tag2) {
    return str.substring(str.lastIndexOf(tag) + 1, str.indexOf(tag2));
  }

  /**
   * 截取两个标记之间的字符串,后标记从后开始查询
   *
   * @param str
   * @param tag
   * @param tag2
   * @return
   */
  public static String substrBetweenOfLastOfLastTag(String str, String tag, String tag2) {
    return str.substring(str.indexOf(tag) + 1, str.lastIndexOf(tag2));
  }

  /**
   * 截取两个标记之间的字符串，一致往后开始查询
   *
   * @param str
   * @param tag
   * @param tag2
   * @return
   */
  public static String substrBetweenOfFirstOfLastTag(String str, String tag, String tag2) {
    int lastIndex = str.indexOf(tag);
    int firstIndex = str.lastIndexOf(tag2);
    if (lastIndex == firstIndex) {
      firstIndex = substrBeforeOfTag(str, tag).lastIndexOf(tag2) + 1;
    }
    return str.substring(firstIndex, lastIndex);
  }

  public static String substrBetweenOfLastOfDoubleTag(String str, String tag, String tag2) {
    int lastIndex = str.lastIndexOf(tag2);
    int firstIndex = str.lastIndexOf(tag);
    if (lastIndex == firstIndex) {
      firstIndex = substrBeforeLastOfTag(str, tag2).lastIndexOf(tag) + 1;
    }
    return str.substring(firstIndex, lastIndex);
  }

  /**
   * 获取最后标记的前面字符串
   *
   * @param str
   * @param tag
   * @return
   */
  public static String substrAfterOfLastTag(String str, String tag) {
    return str.substring(str.lastIndexOf(tag) + 1);
  }

  /**
   * 替换最后一个
   *
   * @param str
   * @param oldTag
   * @param newTag
   * @return
   */
  public static String replaceLast(String str, String oldTag, String newTag) {
    return str.replaceFirst("(?s)" + oldTag + "(?!.*?" + oldTag + ")", newTag);
  }

  public static String replaceLastToEmpty(String str, String oldTag) {
    return str.replaceFirst("(?s)" + oldTag + "(?!.*?" + oldTag + ")", "");
  }

  /**
   * str 的 xml 格式解析
   *
   * @param str
   * @return
   * @throws DocumentException
   */
  public static Map<Object, Object> strParseXml(String str) throws DocumentException {
    Map<Object, Object> map = new HashMap<>();
    if (!str.startsWith("<xml")) {
      str = "<xml>" + str;
    }
    if (!str.endsWith("xml/>")) {
      str = str + "</xml>";
    }
    SAXReader reader = new SAXReader();
    Document document = reader.read(new ByteArrayInputStream(str.getBytes()));
    parsing(document, map);
    return map;
  }

  public static Map<Object, Object> inputStreamParseXml(InputStream is) throws DocumentException {
    Map<Object, Object> map = new HashMap<>(0);
    SAXReader reader = new SAXReader();
    Document document = reader.read(is);
    parsing(document, map);
    return map;
  }

  private static void parsing(Document document, Map<Object, Object> map) {
    Element root = document.getRootElement();
    List<Element> elementList = root.elements();
    for (Element e : elementList) {
      map.put(e.getName(), e.getText());
      returnParseXml(map, e, e.getName());
    }
  }

  private static void returnParseXml(Map<Object, Object> map, Element element, String parentKey) {
    List<Element> elements = element.elements();
    Map<Object, Object> tempMap = new HashMap<>(0);
    if (!elements.isEmpty()) {
      for (Element e : elements) {
        tempMap.put(e.getName(), e.getText());
        returnParseXml(tempMap, e, e.getName());
      }
      map.put(parentKey, tempMap);
    }
  }

  /**
   * 获取组合所有可能性
   *
   * @param sessions
   * @return
   */
  public static <T> List<List<T>> analysisCombination(List<T> sessions) {
    List<List<T>> result = new ArrayList<>();
    peelOffList(sessions, 0, new ArrayList<>(), result);
    return result;
  }

  /**
   * 递归回溯找组合
   *
   * @param sessions
   * @param start
   * @param temp
   * @param result
   */
  private static <T> void peelOffList(
      List<T> sessions, int start, List<T> temp, List<List<T>> result) {
    if (!temp.isEmpty()) {
      result.add(new ArrayList<>(temp));
    }
    for (int i = start; i < sessions.size(); i++) {
      temp.add(sessions.get(i));
      peelOffList(sessions, i + 1, temp, result);
      // 回溯
      temp.remove(temp.size() - 1);
    }
  }
}
